package models

import (
	"context"
	"database/sql"
	"fmt"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"time"

	"group/common"
)

var _ ChatGroupAggregationModel = (*customerChatGroupAggregationModel)(nil)

type (
	ChatGroupAggregationModel interface {
		chatGroupAggregationModel
	}

	customerChatGroupAggregationModel struct {
		conn             sqlx.SqlConn
		chatGroupModel   defaultChatGroupModel
		groupApplyModel  defaultGroupApplyModel
		groupMemberModel defaultGroupMemberModel
	}
)

func NewChatGroupAggregationModel(conn sqlx.SqlConn) ChatGroupAggregationModel {
	return &customerChatGroupAggregationModel{
		conn: conn,
	}
}

type (
	chatGroupAggregationModel interface {
		CreateGroup(ctx context.Context, group *ChatGroup) error
		UpdateGroup(ctx context.Context, group *ChatGroup) error
		HandleGroupApply(ctx context.Context, ID, userID, groupID, status int64) error
		GetGroupCount(ctx context.Context, userID int64) (int64, error)
		GetGroupList(ctx context.Context, userID, offset, limit int64) ([]*ChatGroup, error)
		DeleteMember(ctx context.Context, handleUserID, userID, groupID int64) error
	}
)

func (m *customerChatGroupAggregationModel) CreateGroup(ctx context.Context, group *ChatGroup) error {
	return m.conn.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
		// 创建群
		chatGroupInsertSQL := fmt.Sprintf("INSERT INTO %s (%s) VALUES (?, ?, ?, ?, ?, ?)", m.chatGroupModel.table, chatGroupRowsExpectAutoSet)
		result, err := session.ExecCtx(ctx, chatGroupInsertSQL, group.Name, group.Avatar, group.Desc, group.UserId, group.Status, group.JoinType)
		if err != nil {
			return fmt.Errorf("创建群失败: %w", err)
		}
		groupId, err := result.LastInsertId()
		if err != nil {
			return fmt.Errorf("获取创建群标识失败: %w", err)
		}
		// 将群主写入群成员
		groupMemberInsertSQL := fmt.Sprintf("INSERT INTO %s (%s) VALUES (?, ?, ?, ?, ?, ?, ?)", m.groupMemberModel.table, groupMemberRowsExpectAutoSet)
		_, err = session.ExecCtx(ctx, groupMemberInsertSQL, groupId, group.UserId, "", common.ChatGroupOwner, time.Now(), sql.NullTime{}, common.ChatMemberJoin)
		if err != nil {
			return fmt.Errorf("创建群时将群主写入群成员失败: %w", err)
		}
		return nil
	})
}

func (m *customerChatGroupAggregationModel) UpdateGroup(ctx context.Context, group *ChatGroup) error {
	return m.conn.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
		// 查询群
		var groupInfo ChatGroup
		groupSQL := fmt.Sprintf("SELECT * FROM %s WHERE id = ?", m.chatGroupModel.table)
		err := session.QueryRowCtx(ctx, &groupInfo, groupSQL, group.Id)
		if err != nil {
			return fmt.Errorf("查询群失败: %w", err)
		}
		// 只有管理员或者群主才能修改群信息
		var memberInfo GroupMember
		memberSQL := fmt.Sprintf("SELECT * FROM %s WHERE group_id = ? and user_id = ?", m.groupMemberModel.table)
		err = session.QueryRowCtx(ctx, &memberInfo, memberSQL, group.Id, group.UserId)
		if err != nil {
			return fmt.Errorf("查询群失败: %w", err)
		}
		if memberInfo.Id == 0 {
			return fmt.Errorf("用户不是群成员")
		}
		if memberInfo.Role == common.ChatGroupMember {
			return fmt.Errorf("只有管理员或者群主才能修改群信息")
		}
		// 更新群信息
		updateSQL := fmt.Sprintf("UPDATE %s SET name = ?, avatar = ?, desc = ?, join_type = ?, status = ? WHERE id = ?", m.chatGroupModel.table)
		_, err = session.ExecCtx(ctx, updateSQL, group.Name, group.Avatar, group.Desc, group.JoinType, group.Status, group.Id)
		if err != nil {
			return fmt.Errorf("更新群信息失败: %w", err)
		}
		return nil
	})
}

func (m *customerChatGroupAggregationModel) HandleGroupApply(ctx context.Context, ID, userID, groupID, status int64) error {
	return m.conn.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
		// 找到申请记录
		var applyRec GroupApply
		//applySQL := fmt.Sprintf("SELECT * FROM %s WHERE group_id = ? AND user_id = ?", m.groupApplyModel.table)
		//err := session.QueryRowCtx(ctx, &applyRec, applySQL, groupID, userID)
		applySQL := fmt.Sprintf("SELECT * FROM %s WHERE id = ?", m.groupApplyModel.table)
		err := session.QueryRowCtx(ctx, &applyRec, applySQL, ID)
		if err != nil {
			return fmt.Errorf("查找群申请记录失败: %w", err)
		}
		// 修改申请状态
		applyUpdateSQL := fmt.Sprintf("UPDATE %s SET status = ?, handler_user_id = ?, handle_time = ? WHERE id = ?", m.groupApplyModel.table)
		_, err = session.ExecCtx(ctx, applyUpdateSQL, status, userID, time.Now(), applyRec.Id)
		if err != nil {
			return fmt.Errorf("修改群申请状态失败: %w", err)
		}
		switch status {
		case common.GroupApplyAgree:
			// 同意入群时将用户写入群成员表, 拒绝/取消时不写入
			groupMemberInsertSQL := fmt.Sprintf("INSERT INTO %s (%s) VALUES (?, ?, ?, ?, ?, ?, ?)", m.groupMemberModel.table, groupMemberRowsExpectAutoSet)
			_, err = session.ExecCtx(ctx, groupMemberInsertSQL, groupID, userID, "", common.ChatGroupMember, time.Now(), sql.NullTime{}, common.ChatMemberJoin)
			if err != nil {
				return fmt.Errorf("审核群申请时将用户写入群成员失败: %w", err)
			}
		}
		return nil
	})
}

func (m *customerChatGroupAggregationModel) GetGroupCount(ctx context.Context, userID int64) (int64, error) {
	// 查找用户加入的群聊数量
	var count int64
	groupCountSQL := fmt.Sprintf(
		"SELECT COUNT(a.group_id) FROM %s as a join %s as b on a.group_id = b.id"+
			" WHERE a.user_id = ? and a.status = ? and b.status = ?",
		m.groupMemberModel.table, m.chatGroupModel.table,
	)
	err := m.conn.QueryRowCtx(ctx, &count, groupCountSQL, userID, common.ChatMemberJoin, common.GroupStatusNormal)
	if err != nil {
		return 0, err
	}
	return count, nil
}

func (m *customerChatGroupAggregationModel) GetGroupList(ctx context.Context, userID, offset, limit int64) ([]*ChatGroup, error) {
	// 查找用户加入的群聊列表
	var groupList []*ChatGroup
	groupCountSQL := fmt.Sprintf(
		"SELECT b.* FROM %s as a join %s as b on a.group_id = b.id"+
			" WHERE a.user_id = ? and a.status = ? and b.status = ? order by b.id desc limit ? offset ?",
		m.groupMemberModel.table, m.chatGroupModel.table,
	)
	err := m.conn.QueryRowsCtx(ctx, &groupList, groupCountSQL, userID, common.ChatMemberJoin, common.GroupStatusNormal, limit, offset)
	if err != nil {
		return nil, err
	}
	return groupList, nil
}

func (m *customerChatGroupAggregationModel) DeleteMember(ctx context.Context, handleUserID, userID, groupID int64) error {
	return m.conn.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
		// 自己主动退群或者管理员/群主移除群成员
		var memberInfo GroupMember
		memberSQL := fmt.Sprintf("SELECT * FROM %s WHERE group_id = ? and user_id = ?", m.groupMemberModel.table)
		if handleUserID != userID {
			err := session.QueryRowCtx(ctx, &memberInfo, memberSQL, groupID, handleUserID)
			if err != nil {
				return fmt.Errorf("查询群成员失败: %w", err)
			}
			if memberInfo.Id == 0 {
				return fmt.Errorf("用户不是群成员")
			}
			if memberInfo.Role == common.ChatGroupMember {
				return fmt.Errorf("只有管理员或者群主才能删除群成员")
			}
		}
		// 查询群成员信息
		err := session.QueryRowCtx(ctx, &memberInfo, memberSQL, groupID, userID)
		if err != nil {
			return fmt.Errorf("查询群成员失败: %w", err)
		}
		if memberInfo.Id == 0 {
			return fmt.Errorf("用户不是群成员")
		}
		if memberInfo.Role == common.ChatGroupOwner {
			return fmt.Errorf("群主不能退群")
		}
		// 移除成员
		updateSQL := fmt.Sprintf("UPDATE %s SET status = ? WHERE id = ?", m.groupMemberModel.table)
		_, err = session.ExecCtx(ctx, updateSQL, common.ChatMemberQuit, memberInfo.Id)
		if err != nil {
			return fmt.Errorf("更新群成员状态失败: %w", err)
		}
		return nil
	})
}
